package com.yang.utils;

import cn.hutool.core.lang.UUID;
import com.yang.service.ILock;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.Collections;
import java.util.concurrent.TimeUnit;



/**
 * <p>
 *  基于redis实现的分布式锁
 * </p>
 *
 * @author yang
 * @since 2022-10-22
 */
public class SimpleRedisLock implements ILock {

    private static final String KEY_PREFIX = "lock:";

    private final String name;

    private final StringRedisTemplate stringRedisTemplate;

    private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-";

    private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;



    static {
        UNLOCK_SCRIPT = new DefaultRedisScript<>();
        UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
        UNLOCK_SCRIPT.setResultType(Long.class);
    }

    public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {
        this.name = name;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public boolean tryLock(long timeoutSec) {
        String key = KEY_PREFIX + name;
        //1.获取线程标识
        String threadId = ID_PREFIX + Thread.currentThread().getId();

        //2.获取锁,通过setNx的方式，key是前缀+名字，value是线程标识
        Boolean success = stringRedisTemplate.opsForValue().setIfAbsent
                (key, threadId, timeoutSec, TimeUnit.SECONDS);

        return Boolean.TRUE.equals(success);
    }
    @Override
    public void unlock() {
        // 调用lua脚本
        stringRedisTemplate.execute(
                UNLOCK_SCRIPT,
                Collections.singletonList(KEY_PREFIX + name),
                ID_PREFIX + Thread.currentThread().getId());

    }

}

//    @Override
//    public void unlock() {
//        //1.获取线程标识
//        String threadId = ID_PREFIX + Thread.currentThread().getId();
//        //2.获取所种的标识
//        String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);
//        //3.判断标识是否一致
//        if (threadId.equals(id)){
//            //一致，则释放
//            stringRedisTemplate.delete(KEY_PREFIX + name);
//        }
//    }
//    private final String name;
//    private final StringRedisTemplate stringRedisTemplate;
//
//    public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {
//        this.name = name;
//        this.stringRedisTemplate = stringRedisTemplate;
//    }
//
//    private static final String KEY_PREFIX = "lock:";
//    private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-";
//    private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;
//static {
//        UNLOCK_SCRIPT = new DefaultRedisScript<>();
//        UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
//        UNLOCK_SCRIPT.setResultType(Long.class);
//        }
//
///**
// * 获取锁，同时放入到线程id，解决分布式的锁误删的问题
// * 同时使用lua脚本，来保证分布式锁里面的原子性问题
// * @param timeoutSec 锁持有的超时时间，过期后自动释放
// * @return 获取锁成功或者失败
// */
//@Override
//public boolean tryLock(long timeoutSec) {
//        // 获取线程标示
//        String threadId = ID_PREFIX + Thread.currentThread().getId();
//        // 获取锁
//        Boolean success = stringRedisTemplate.opsForValue()
//        .setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);
//        return Boolean.TRUE.equals(success);
//        }
//
///**
// * 释放锁，判断要释放的锁的id和当前线程的id是否一致，一致则释放
// * 同时使用lua脚本，来保证分布式锁里面的原子性问题
// */
//@Override
//public void unlock() {
//        // 调用lua脚本
//        stringRedisTemplate.execute(
//        UNLOCK_SCRIPT,
//        Collections.singletonList(KEY_PREFIX + name),
//        ID_PREFIX + Thread.currentThread().getId());
//        }
